﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel;

namespace ProgNetComponents.Design.Attributes
{
    /// <summary>
    /// PropertyDescriptor for properties
    /// </summary>
    public class PropertyInfoDescriptor : PropertyDescriptor
    {

        private PropertyInfo propInfo;
        /// <summary>
        /// Creates PropertyInfoDescriptor instance
        /// </summary>
        /// <param name="prop"></param>
        /// <param name="attribs"></param>
        public PropertyInfoDescriptor(PropertyInfo prop, params Attribute[] attribs)
            : base(prop.Name, attribs)
        {
            propInfo = prop;
        }

        private object DefaultValue
        {
            get
            {
                if (propInfo.IsDefined(typeof(DefaultValueAttribute), false))
                {
                    return ((DefaultValueAttribute)propInfo.GetCustomAttributes(typeof(DefaultValueAttribute), false)[0]).Value;
                }
                return PropertyType.IsValueType ? Activator.CreateInstance(PropertyType) : null;
            }
        }
        /// <summary>
        /// Gets if property is readonly
        /// </summary>
        public override bool IsReadOnly
        {
            get { return this.Attributes.Contains(System.ComponentModel.ReadOnlyAttribute.Yes) ||
                this.Attributes.Contains(System.ComponentModel.BrowsableAttribute.No); }
        }
        /// <summary>
        /// Gets property value for specified component
        /// </summary>
        /// <param name="component"></param>
        /// <returns></returns>
        public override object GetValue(object component)
        {
            return propInfo.GetValue(component, null);
        }
        /// <summary>
        /// Getst if value can be reset
        /// </summary>
        /// <param name="component"></param>
        /// <returns></returns>
        public override bool CanResetValue(object component)
        {
            return (!this.IsReadOnly & (this.DefaultValue != null && !this.DefaultValue.Equals(this.GetValue(component))));
        }
        /// <summary>
        /// Resets value
        /// </summary>
        /// <param name="component"></param>
        public override void ResetValue(object component)
        {
            this.SetValue(component, this.DefaultValue);
        }
        /// <summary>
        /// Sets value of property
        /// </summary>
        /// <param name="component"></param>
        /// <param name="value"></param>
        public override void SetValue(object component, object value)
        {
            propInfo.SetValue(component, value, null);
        }
        /// <summary>
        /// Specifies if property should be serialized
        /// </summary>
        /// <param name="component"></param>
        /// <returns></returns>
        public override bool ShouldSerializeValue(object component)
        {
            if (this.Attributes.Contains(AlwaysSerializeAttribute.Yes))
                return true;
            if (this.IsReadOnly)
                return false;
            object value1 = this.GetValue(component);
            object v2 = DefaultValue;
            
            if (v2.EqualsSafe(value1))
                return false;
            return true;
        }
        /// <summary>
        /// Returns component type
        /// </summary>
        public override Type ComponentType
        {
            get
            {
                return propInfo.DeclaringType;
            }
        }
        /// <summary>
        /// returns property type
        /// </summary>
        public override Type PropertyType
        {
            get
            {
                return propInfo.PropertyType;
            }
        }

    }
}
